<?php


namespace App\Services\Pc\Invoice;


use App\Exceptions\DingoException;
use App\Libraries\BaiwangInvoice;
use App\Models\Pc\Invoice\FinanceInvoice;
use App\Models\Pc\Invoice\FinanceInvoiceDetail;
use App\Models\Pc\SalesContact\ShipmentContractDetails;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;

class InvoiceService
{

    public $financeInvoice;
    public $financeInvoiceDetails;

    public function __construct()
    {
        $this->financeInvoice = new FinanceInvoice();
        $this->financeInvoiceDetails = new FinanceInvoiceDetail();
    }


    /**
     * 新增
     *
     * @param $input
     * @param $user
     * @return bool
     * @throws DingoException
     */
    public function add($input,$user)
    {
        //获取入库数组
        $time = now();
        $data = [
            'company_id'                 => $user->company_id,
            'bill_num'                   => $input['bill_num'],
            'invoice_num'                => $input['invoice_num'] ?? '',
            'invoice_direction'          => $input['invoice_direction'] ?? 1,
            'date'                       => $input['date'] ?? $time,
            'invoice_category'           => $input['invoice_category'] ?? 1,
            'invoice_type'               => $input['invoice_type'] ?? 1,
            'statement_customer_id'      => $input['statement_customer_id'] ?? 0,
            'statement_customer_tax_num' => $input['statement_customer_tax_num'] ?? '',
            'statement_customer_addr'    => $input['statement_customer_addr'] ?? '',
            'statement_customer_tel'     => $input['statement_customer_tel'] ?? '',
            'statement_customer_account' => $input['statement_customer_account'] ?? '',
            'statement_customer_bank'    => $input['statement_customer_bank'] ?? '',
            'remark'                     => $input['remark'] ?? '',
            'is_invoice'                 => 0,
            'is_print'                   => 0,
            'status'                     => 1,
            'create_userid'              => $user->id,
            'created_at'                 => $time,
        ];

        //明细表数据
        $data_details = $input['details'] ?? [];

        if (empty($data_details)) {
            throw new DingoException("产品信息不能为空", 422);
        }


        //需要合并的数组
        $data_merge = [
            'bill_num_invoice' => $input['bill_num'],
            'invoice_direction' => $input['invoice_direction'] ?? 1,
            'company_id' => $user->company_id,
            'status' => 1,
            'create_userid' => $user->id,
            'created_at' => $time,
        ];
        $total_num = 0;
        $total_weight = 0;
        $total_invoice_money = 0; //发票金额总和
        $update_shipment_details = [];
        foreach ($data_details as &$value) {

            $data_arr = $this->setDetailsList($value, $input['bill_num']);

            $value = array_merge($data_arr, $data_merge);//数据合并
            //回写数据
            $update_shipment_details[] = [
                'type'     => 'add',
                'bill_num' => $value['makeinv_bill_num'],
                'num'      => $value['num'] ?? 0,
                'weight'   => $value['weight'] ?? 0
            ];
            //总量 数量，重量
            $total_num += $data_arr['num'];
            $total_weight += $data_arr['weight'];
            $total_invoice_money += $data_arr['tax_money'];
        }
        $data['tax_money'] = $total_invoice_money;
        $data['num'] = $total_num;
        $data['weight'] = $total_weight;

//        dd($data,$data_details,$update_shipment_details);

        DB::beginTransaction();
        try {
            $this->financeInvoice->insert($data);
            $this->financeInvoiceDetails->insert($data_details);
            if (!empty($update_shipment_details)){
                $this->writeBackLock($update_shipment_details);
            }

            DB::commit();
        } catch (QueryException $e) {

            DB::rollBack();
            \Log::info($e->getMessage());
            return false;
        }
        return true;

    }


    /**
     * 修改
     * @param $input
     * @param $user
     * @return bool
     * @throws DingoException
     */
    public function update($input,$user)
    {
        $time = now();
        //打印完成不能修改
        $old = $this->financeInvoice
            ->where('status', 1)
            ->where('bill_num', $input['bill_num'])
            ->select(['is_invoice'])
            ->first();
        if (!$old){
            throw new DingoException("参数错误！", 422);
        }
        if ($old->is_invoice == 1){
            throw new DingoException("开完票咯不能修改哟！", 422);
        }
        //获取明细编辑数据(编辑,新增,删除)
        $data_details = $input['details'];
        if (empty($data_details)) {
            throw new DingoException("产品信息不能为空", 422);
        }

        //根据主表查出原有明细表数据数组
        $select = [
            'id',
            'makeinv_bill_num',
            'num',
            'weight',
        ];
        $details_id_oldarr = $this->financeInvoiceDetails->select($select)
            ->where([['bill_num_invoice', $input['bill_num']], ['status', 1]])
            ->get();

        $details_id_oldarr = obj2array($details_id_oldarr);
        // 筛出编辑明细 id
        $details_id_arr = array_column($data_details, 'id');
        // 筛出删除的明细 id
        $details_id_del_arr = array_diff(array_column($details_id_oldarr, 'id'), $details_id_arr);

        $data = [
            'company_id'                 => $user->company_id,
            'invoice_num'                => $input['invoice_num'] ?? '',
            'invoice_direction'          => $input['invoice_direction'] ?? 1,
            'date'                       => $input['date'] ?? $time,
            'invoice_category'           => $input['invoice_category'] ?? 1,
            'invoice_type'               => $input['invoice_type'] ?? 1,
            'statement_customer_id'      => $input['statement_customer_id'] ?? 0,
            'statement_customer_tax_num' => $input['statement_customer_tax_num'] ?? '',
            'statement_customer_addr'    => $input['statement_customer_addr'] ?? '',
            'statement_customer_tel'     => $input['statement_customer_tel'] ?? '',
            'statement_customer_account' => $input['statement_customer_account'] ?? '',
            'statement_customer_bank'    => $input['statement_customer_bank'] ?? '',
            'remark'                     => $input['remark'] ?? '',
            'is_invoice'                 => 0,
            'is_print'                   => 0,
            'status'                     => 1,
            'create_userid'              => $user->id,
            'created_at'                 => $time,
        ];


        //筛选出要新增的明细数据和要编辑的明细数据
        $add_data_arr = [];//新增数据
        $edit_data_arr = [];//编辑数据

        //需要合并的数组
        $add_data_merge = [
            'invoice_direction' => $input['invoice_direction'] ?? 1,
            'status' => 1,
            'company_id' => $user->company_id,
            'bill_num_invoice' => $input['bill_num'],
            'create_userid' => $user->id,
            'created_at' => $time
        ];

        $edit_data_merge = [
            'create_userid' => $user->id,
            'update_userid' => $user->id,
            'updated_at'    => $time
        ];

        $total_num = 0;
        $total_weight = 0;
        $total_invoice_money = 0;
        $old_details_update = [];//老的数据
        $update_details_update = []; //新的数据
        foreach ($details_id_oldarr as $item){
            $old_details_update[] = [
                'type'     => 'edit',
                'bill_num' => $item['makeinv_bill_num'],
                'num'      => $item['num'] ?? 0,
                'weight'   => $item['weight'] ?? 0
            ];
        }
        foreach ($data_details as &$value) {

            $data_arr = $this->setDetailsList($value, $input['bill_num']);
            if (!empty($value['id'])) {
                //追加id 到第一个key 用于批量更新
                $data_arr = collect($data_arr);
                $data_arr->prepend($value['id'], 'id');
                $data_arr = $data_arr->toArray();
                $edit_data_arr[] = array_merge($data_arr, $edit_data_merge);
                //set_inventory 编辑 的数据 整理
                $temp_k = collect($details_id_oldarr)->where('id', $data_arr['id'])->all();
                $temp_k = array_format($temp_k);
                if (empty($temp_k)) {
                    throw new DingoException('编辑的 id 不存在',422);
                }
            } else {
                $bill_num_details = create_bill_num_details($input['bill_num']);
                $bill_num_details_arr = ['bill_num' => $bill_num_details];
                $add_data_arr[] = array_merge($data_arr, $add_data_merge, $bill_num_details_arr);
            }
            $update_details_update[] = [
                'type'     => 'add',
                'bill_num' => $value['makeinv_bill_num'],
                'num'      => $value['num'] ?? 0,
                'weight'   => $value['weight'] ?? 0
            ];
            //总量 数量，重量
            $total_num += $data_arr['num'];
            $total_weight += $data_arr['weight'];
            $total_invoice_money += $data_arr['tax_money'];

        }
        $data['num'] = $total_num;
        $data['weight'] = $total_weight;
        $data['tax_money'] = $total_invoice_money;
//        dd($data,$old_details_update,$edit_data_arr,$add_data_arr,$update_details_update);
        DB::beginTransaction();
        try {
            // （1） 主表编辑
            $this->financeInvoice->where("id", $input["id"])->update($data);
            //先删除锁定量
            if (!empty($old_details_update)){
                $this->writeBackLock($old_details_update);
            }
            //  明细表删除
            $this->financeInvoiceDetails->whereIn("id", $details_id_del_arr)->update(['status' => 0]);
            //  明细表编辑
            updateBatch($edit_data_arr, 'finance_invoice_detail');//批量更新
            //  明细表新增
            $this->financeInvoiceDetails->insert($add_data_arr);
            //在一次锁定量
            if (!empty($update_details_update)){
                $this->writeBackLock($update_details_update);
            }
            DB::commit();
        } catch (QueryException $e) {

            DB::rollBack();
            \Log::info($e->getMessage());
            return false;
        }
        return true;

    }

    /**
     * 明细表
     *
     * @param $value
     * @param string $bill_num
     * @return array
     */
    public function setDetailsList($value, $bill_num = '')
    {
        $data_arr = [
            'makeinv_bill_num'                   => $value['makeinv_bill_num'] ?? 0, //业务单号
            'categorys_small_id'                 => $value['categorys_small_id'] ?? 0,
            'categorys_small_name'               => $value['categorys_small_name'] ?? '',
            'steel_mill_id'                      => $value['steel_mill_id'] ?? 0,
            'steel_mill_name'                    => $value['steel_mill_name'] ?? '',
            'materials_id'                       => $value['materials_id'] ?? 0,
            'materials_name'                     => $value['materials_name'] ?? '',
            'specs_id'                           => $value['specs_id'] ?? 0,
            'specs_name'                         => $value['specs_name'] ?? '',
            'unit_of_measurement'                => $value['unit_of_measurement'] ?? '',
            'num'                                => $value['num'] ?? 0,
            'weight'                             => $value['weight'] ?? 0,
            'tax_price'                          => $value['tax_price'] ?? 0,
            'tax_money'                          => $value['tax_money'] ?? 0,
            'price'                              => $value['price'] ?? 0,
            'money'                              => $value['money'] ?? 0,
            'tax_rate'                           => $value['tax_rate'] ?? 0,
            'tax_diff_money'                     => $value['tax_diff_money'] ?? 0,
            'remark'                             => $value['remark'] ?? '',
        ];
        if (!empty($bill_num)) {
            $data_arr['bill_num'] = create_bill_num_details($bill_num);
        }
        return $data_arr;
    }


    /**
     * 回写锁定
     *
     * bill_num 明细单据号
     *
     * @return bool
     */
    public function writeBackLock($data = [])
    {

        $bill_num_arr = [];
        $update_data = [];
        foreach ($data as  $bv) {
            $bill_num_arr[] = $bv['bill_num'];
        }
        $list_re = ShipmentContractDetails::query()
            ->where('status', 1)
            ->whereIn('bill_num', $bill_num_arr)
            ->get();

        $list_unit_of_measurement = $list_re->pluck('unit_of_measurement', 'bill_num'); //数量
        $list_num = $list_re->pluck('num', 'bill_num'); //数量
        $list_num_exec = $list_re->pluck('num_exec', 'bill_num'); //执行数量
        $list_num_locking = $list_re->pluck('num_locking', 'bill_num');//锁定数量
        $list_weight = $list_re->pluck('weight', 'bill_num');//重量
        $list_weight_exec = $list_re->pluck('weight_exec', 'bill_num');//执行重量
        $list_weight_locking = $list_re->pluck('weight_locking', 'bill_num');//锁定数量

        foreach ($data as $v) {
            switch ($v['type']) {
                case 'add':
                    $list_num_unexec = $list_num[$v['bill_num']] - $list_num_exec[$v['bill_num']] - $list_num_locking[$v['bill_num']]; //未执行 数量
                    $list_weight_unexec = $list_weight[$v['bill_num']] - $list_weight_exec[$v['bill_num']] - $list_weight_locking[$v['bill_num']];  //未执行 重量
                    if ($list_unit_of_measurement[$v['bill_num']] == 1) { //安装重量
                        if ($v['weight'] > $list_weight_unexec) {
                            throw new DingoException("重量超过最大引用值", 422);
                        }
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => 0,
                            'weight_locking' => ($list_weight_locking[$v['bill_num']] + $v['weight']),
                        ];
                    } else {
                        if ($v['num'] > $list_num_unexec) {
                            throw new DingoException("数量超过最大引用值", 422);
                        }
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => ($list_num_locking[$v['bill_num']] + $v['num']),
                            'weight_locking' => 0,
                        ];
                    }
                    break;
                case 'edit':
                    $list_num_p = $list_num_locking[$v['bill_num']] - $v['num'];
                    $list_weight_p = $list_weight_locking[$v['bill_num']] - $v['weight'];
                    if ($list_unit_of_measurement[$v['bill_num']] == 1) { //安装重量
                        if ($list_weight_p < 0){
                            throw new DingoException("还的重量错误", 422);
                        }
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => 0,
                            'weight_locking' => $list_weight_p,
                        ];
                    } else {
                        if ($list_num_p < 0){
                            throw new DingoException("还的数量错误", 422);
                        }
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => $list_num_p,
                            'weight_locking' => 0,
                        ];
                    }
                    break;
            }
        }
        updateBatch($update_data, 'shipment_contract_details');
        return true;

    }

    /**
     * 分页
     *
     * @param $where
     * @param $params
     * @param $page_size
     * @return array
     */
    public function getPaginate($where,$params,$page_size)
    {
        $query = $this->financeInvoice->with(['details'])
            ->where($where);

        !empty($params['categorys_small_id']) && $query = $query->whereHas('details', function ($q) use ($params) {
            $q->where('categorys_small_id', $params['categorys_small_id']);
        });//品名
        !empty($params['materials_id']) && $query = $query->whereHas('details', function ($q) use ($params) {
            $q->where('materials_id', $params['materials_id']);
        });//材质ID
        !empty($params['specs_id']) && $query = $query->whereHas('details', function ($q) use ($params) {
            $q->where('specs_id', $params['specs_id']);
        });//品名
        !empty($params['steel_mill_id']) && $query = $query->whereHas('details', function ($q) use ($params) {
            $q->where('steel_mill_id', $params['steel_mill_id']);
        });//钢厂ID
        $copy = $query->get();
        $data = $query->latest('id')->paginate($page_size);
        $all_page_sum = ['all_page_sum'=>[
            'num_sum'=>"0.00",
            'weight_sum'=>"0.00",
            'tax_money_sum'=>"0.00",
        ]];
        foreach ($copy as $item){
            $all_page_sum['all_page_sum']['num_sum'] +=  $item->details->sum('num') ?? 0;
            $all_page_sum['all_page_sum']['weight_sum'] +=  $item->details->sum('weight') ?? 0;
            $all_page_sum['all_page_sum']['tax_money_sum'] +=  $item->details->sum('tax_money') ?? 0;
        }

        return cache_format_data($data,'',$all_page_sum);
    }

    /**
     * 详情
     *
     * @param $bill_num
     * @param $user
     * @return mixed
     * @throws DingoException
     */
    public function show($bill_num,$user)
    {
        if (empty($bill_num)){
            throw new DingoException("参数错误", 422);
        }
        $where = [
            ['bill_num',$bill_num],
            ['company_id',$user->company_id],
            ['status',1],
        ];
        $data = $this->financeInvoice->with(['details'])->where($where)->first();
        if (empty($data)){
            throw new DingoException("产品信息不存在", 422);
        }

        return cache_format_data_first($data);
    }


    /**
     * 发票浏览
     *
     * @param $bill_num
     * @param $user
     * @return mixed
     * @throws DingoException
     */
    public function salesInvoicePrintPreview($bill_num,$user)
    {
        $main_arr = FinanceInvoice::query()->where('status', 1)
            ->where('company_id',$user->company_id)
            ->where('bill_num', $bill_num)
            ->first();
        $main_arr = obj2array($main_arr);
        if (empty($main_arr)){
            throw new DingoException("未找到相应数据", 422);
        }
        if ($main_arr['baiwang_response'] == '') {
            throw new DingoException("未找到发票预览内容", 422);
        }
        $model =  (new BaiwangInvoice());
        $method = 'baiwang.invoice.query';//发票查询
        $body = $model->getPreviewParam($main_arr,$user);
        $open_public_param = $model->getInviceOpenPublicParam($method, $body);
        $url = config('baiwang.bw_api_url').'?'.http_build_query($open_public_param);
        $request_res = $this->requestPost($url, $body);
        $request_res_arr = json_decode($request_res, true);
        if (isset($request_res_arr['response'])) {
            return $request_res_arr['response']['invoiceList'][0];

        } elseif(isset($request_res_arr['errorResponse'])) {
            throw new DingoException($request_res_arr['errorResponse']['subMessage'],422);

        } else {
            throw new DingoException('请求失败',422);
        }
    }



    /**
     * 发票作废
     *
     * @param $bill_num
     * @param $user
     * @return string
     * @throws DingoException
     */
    public function salesInvoiceInvalid($bill_num,$user)
    {
        $time = now();
        $main_arr = FinanceInvoice::query()
            ->where('status', 1)
            ->where('bill_num', $bill_num)
            ->first();
        $main_arr = obj2array($main_arr);
        if (empty($main_arr)){
            throw new DingoException("未找到相应数据", 422);
        }
        if ($main_arr['baiwang_response'] == ''){
            throw new DingoException("未找到发票内容", 422);
        }
        $model =  (new BaiwangInvoice());
        $method = 'baiwang.invoice.invalid';//发票作废
        $body = $model->getInvalidParam($main_arr, $user);
        $open_public_param = $model->getInviceOpenPublicParam($method, $body);
        $url = config('baiwang.bw_api_url').'?'.http_build_query($open_public_param);
        $request_res = $this->requestPost($url, $body);
        $request_res_arr = json_decode($request_res, true);
        if (isset($request_res_arr['response'])) {
            //保存到finance_invoice表中
            $update = [
                'invoice_num' => '',
                'invoice_date' => null,
                'baiwang_response' => '',
                'is_print' => 0,
                'is_invoice' => 0,
            ];
            FinanceInvoice::query()->where('bill_num', $bill_num)
                ->update($update);
            //执行数量重量变化成锁定重量数量
            $this->returnInventory($bill_num);

            return '操作成功';

        } elseif(isset($request_res_arr['errorResponse'])) {
            throw new DingoException($request_res_arr['errorResponse']['subMessage'],422);

        } else {
            throw new DingoException('请求失败',422);
        }
    }


    /**
     * 执行数量重量变化成锁定重量数量
     *
     * @param $bill_num
     * @return bool
     * @throws DingoException
     */
    public function returnInventory($bill_num)
    {
        $data = FinanceInvoiceDetail::query()->where('status',1)->where('bill_num_invoice',$bill_num)->get();
        $update_data = [];
        foreach ($data as $item){
            $update_data[] = [
                'type'=>'return_inventory',
                'bill_num'=>$item['makeinv_bill_num'],
                'num'=>$item['num'] ?? 0,
                'weight'=>$item['weight'] ?? 0,
            ];
        }
        if (!empty($update_data)){
            //回写执行
            $this->writeBackExecution($update_data);
        }
        return true;
    }

    /**
     * 回写执行
     *
     * bill_num 明细单据号
     *
     * @return bool
     */
    public function writeBackExecution($data = [])
    {

        $bill_num_arr = [];
        $update_data = [];
        foreach ($data as  $bv) {
            $bill_num_arr[] = $bv['bill_num'];
        }
        $list_re = ShipmentContractDetails::query()
            ->where('status', 1)
            ->whereIn('bill_num', $bill_num_arr)
            ->get();

        $list_unit_of_measurement = $list_re->pluck('unit_of_measurement', 'bill_num'); //数量
        $list_num_exec = $list_re->pluck('num_exec', 'bill_num'); //执行数量
        $list_num_locking = $list_re->pluck('num_locking', 'bill_num');//锁定数量
        $list_weight_exec = $list_re->pluck('weight_exec', 'bill_num');//执行重量
        $list_weight_locking = $list_re->pluck('weight_locking', 'bill_num');//锁定数量

        foreach ($data as $v) {
            switch ($v['type']) {
                case 'bound_inventory': //绑定货
                    if ($list_unit_of_measurement[$v['bill_num']] == 1) { //安装重量
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => 0,
                            'num_exec' => 0,
                            'weight_locking' => ($list_weight_locking[$v['bill_num']] - $v['weight']),
                            'weight_exec' => ($list_weight_exec[$v['bill_num']] + $v['weight']),
                        ];
                    } else {
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => ($list_num_locking[$v['bill_num']] - $v['num']),
                            'num_exec' => ($list_num_exec[$v['bill_num']] + $v['num']),
                            'weight_locking' => 0,
                            'weight_exec' => 0,
                        ];
                    }
                    break;
                case 'return_inventory': //退货
                    if ($list_unit_of_measurement[$v['bill_num']] == 1) { //安装重量
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => 0,
                            'num_exec' => 0,
                            'weight_locking' => ($list_weight_locking[$v['bill_num']] + $v['weight']),
                            'weight_exec' => ($list_weight_exec[$v['bill_num']] - $v['weight']),
                        ];
                    } else {
                        $update_data[] = [
                            'bill_num' => $v['bill_num'],
                            'num_locking' => ($list_num_locking[$v['bill_num']] + $v['num']),
                            'num_exec' => ($list_num_exec[$v['bill_num']] - $v['num']),
                            'weight_locking' => 0,
                            'weight_exec' =>0,
                        ];
                    }
                    break;
            }
        }
        updateBatch($update_data, 'shipment_contract_details');
        return true;

    }


    /**
     * 打印
     *
     * @param $bill_num
     * @param $user
     * @return mixed
     * @throws DingoException
     */
    public function salesInvoicePrint($bill_num,$user)
    {
        $main_arr = FinanceInvoice::query()->where('status', 1)->where('bill_num', $bill_num)->first();
        $main_arr = obj2array($main_arr);
        if (empty($main_arr)) {
            throw new DingoException('未找到相应数据',422);
        }
        if ($main_arr['baiwang_response'] == ''){
            throw new DingoException('未找到发票内容',422);
        }

        if ($main_arr['is_print'] == 1){
            throw new DingoException('已经打印过，不可再次打印',422);
        }
        $model =  (new BaiwangInvoice());
        $method = 'baiwang.invoice.print';//发票打印
        $body = $model->getPrintParam($main_arr,$user);
        $open_public_param = $model->getInviceOpenPublicParam($method, $body);
        $url = config('baiwang.bw_api_url').'?'.http_build_query($open_public_param);
        $request_res = $this->requestPost($url, $body);
        $request_res_arr = json_decode($request_res, true);
        if (isset($request_res_arr['response'])) {//发票打印成功
            $this->financeInvoice::query()->where('bill_num',$bill_num)->update(['is_print'=>1]);
            return $request_res_arr['response']['message'];
        } elseif(isset($request_res_arr['errorResponse'])) {
            throw new DingoException($request_res_arr['errorResponse']['subMessage'],422);

        } else {
            throw new DingoException('请求失败',422);
        }
    }



    /**
     * 开票
     *
     * @param $bill_num
     * @param $user
     * @return bool
     * @throws DingoException
     */
    public function salesInvoiceOpen($bill_num,$user)
    {
        $main_arr = $this->financeInvoice->where('status', 1)->where('bill_num', $bill_num)->first();
        $main_arr = obj2array($main_arr);
        if (empty($main_arr)) {
            throw new DingoException('未找到相应数据',422);
        }
        if ($main_arr['invoice_direction'] != 1) {
            throw new DingoException('目前只有出货单才能开具发票',422);
        }
        if ($main_arr['invoice_num'] != ''){
            throw new DingoException('已经开具发票，不可再次开具',422);
        }
        $main_arr = cache_format_data_first($main_arr);
        $detail_arr = $this->financeInvoiceDetails->where('status', 1)->where('bill_num_invoice', $bill_num)->get()->toArray();
        $detail_arr = cache_format_new_data($detail_arr);
//        dd($detail_arr);

        $method = 'baiwang.invoice.open';//发票开具
        $model =  (new BaiwangInvoice());
        $body = $model->getOpenParam($main_arr, $detail_arr,$user);//获取业务参数
//        dd($body);
        $open_public_param = $model->getInviceOpenPublicParam($method, $body);//获取公共参数
        $url = config('baiwang.bw_api_url').'?'.http_build_query($open_public_param);
        $request_res = $this->requestPost($url, $body);
        $request_res_arr = json_decode($request_res, true);
        if (isset($request_res_arr['response'])) {
            //保存到finance_invoice表中
            $response_update_arr = [
                'invoice_num' => $request_res_arr['response']['invoiceNo'],
                'is_invoice' => 1,
                'invoice_date' => now(),
                'baiwang_response' => $request_res,
            ];
            //修改发票主表
            if (!empty($response_update_arr)){
                $this->financeInvoice::query()->where('bill_num',$bill_num)->update($response_update_arr);
            }
            //出库单进行绑定
            $this->boundInventory($bill_num);
            return true;//请求成功

        } elseif(isset($request_res_arr['errorResponse'])) {
            throw new DingoException($request_res_arr['errorResponse']['subMessage'],422);

        } else {
            throw new DingoException('请求失败',422);
        }
    }


    /**
     * 出库单进行绑定
     * @param $bill_num
     * @return bool
     */
    public function boundInventory($bill_num)
    {
        $data = FinanceInvoiceDetail::query()->where('status',1)->where('bill_num_invoice',$bill_num)->get();
        $update_data = [];
        foreach ($data as $item){
            $update_data[] = [
                'type'=>'bound_inventory',
                'bill_num'=>$item['makeinv_bill_num'],
                'num'=>$item['num'] ?? 0,
                'weight'=>$item['weight'] ?? 0,
            ];
        }
        if (!empty($update_data)){
            //回写执行
            $this->writeBackExecution($update_data);
        }
        return true;
    }


    //发送post请求
    protected function requestPost($url, $data)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
        curl_setopt($ch, CURLOPT_HEADER,0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $res = curl_exec($ch);
        curl_close($ch);
        return $res;
    }
}